package ldh.serialize;

import ldh.serialize.create.MakerConfig;
import ldh.serialize.freemaker.FreeMaker;
import ldh.serialize.register.Register;
import ldh.serialize.type.ArraySerialized;
import ldh.serialize.type.EnumSerialized;
import ldh.serialize.type.IterableSerialized;
import ldh.serialize.type.MapSerialized;
import ldh.serialize.util.ClassInfo;
import ldh.serialize.util.ClassInfo.ClassData;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class Maker {

	
	public static void main(String[] args) {
		String ftl = "mapper.ftl";
		MakerConfig config = new MakerConfig();
		config.className("ldh.User").className("ldh.Level").className("ldh.SexEnum").className("ldh.LdhUser");
		List<ClassInfo> configs = config.getClassInfoes();
		
		for (ClassInfo info : configs) {
			Map<Object, Object> data = new HashMap<Object, Object>();
			String beanName = info.getClazz().getSimpleName();
			data.put("beanName", beanName);
			data.put("classInfo", info);
			data.put("basePackage", info.getClazz().getPackage());
			Set<String> imports = new HashSet<String>();
			imports.add(info.getClazz().getName());
			imports(info, imports);
			data.put("imports", imports);
			
			
			FreeMaker freeMaker = new FreeMaker();
			freeMaker.setFileName(beanName + "Serialize.java");
			freeMaker.setBasePath("E:\\project\\ldh\\avro-test\\StupidBear\\src\\test\\java");
			String p = info.getClazz().getPackage().getName();
			
			
			String sp = System.getProperty("file.separator");
			p = p.replace(".", sp);
			freeMaker.setOutPath(p);
			freeMaker.out(ftl, data);
		}
		
	}
	
	public static void imports(ClassInfo classInfo, Set<String> imports) {
		Set<ClassData> classDatas = classInfo.getDatas();
		for (ClassData classData : classDatas) {
			Class<?> clazz = classData.getField().getType();
			
			if (!clazz.isPrimitive()) {
				imports.add(clazz.getName());
			}
			
			Serialized<?> serialized = Register.getInstance().getSerialized(clazz);
			if (serialized != null) {
				imports.add(serialized.getClass().getName());
				continue;
			}
			
			if (clazz.isArray()) {
				clazz = clazz.getComponentType();
				serialized = Register.getInstance().getSerialized(clazz);
				if (serialized == null) {
					throw new RuntimeException("not this class:" + clazz);
				}
				imports.add(serialized.getClass().getName());
				imports.add(ArraySerialized.class.getName());
			} else if (clazz.isEnum()) {
				imports.add(EnumSerialized.class.getName());
			}  else if (Iterable.class.isAssignableFrom(clazz)) {
				Type type = classData.getField().getGenericType();
				if (type instanceof ParameterizedType) {
					ParameterizedType parameterizedType = (ParameterizedType)type;
		            Type basicType = parameterizedType.getRawType();   
		            Type[] types = parameterizedType.getActualTypeArguments();   
		            Class<?> key = (Class<?>) types[0];
		            Serialized<?> keySerialized = Register.getInstance().getSerialized(key);
		            imports.add(keySerialized.getClass().getName());
		            imports.add(IterableSerialized.class.getName());
		            continue;
				}
				serialized = Register.getInstance().getSerialized(clazz);
				if (serialized == null) {
					throw new RuntimeException("not this class:" + clazz);
				}
				imports.add(serialized.getClass().getName());
			} else if (Map.class.isAssignableFrom(clazz)) {
				Type type = classData.getField().getGenericType();
				if (type instanceof ParameterizedType) {
					ParameterizedType parameterizedType = (ParameterizedType)type;
		            Type basicType = parameterizedType.getRawType();   
		            Type[] types = parameterizedType.getActualTypeArguments();   
		            Class<?> key = (Class<?>) types[0];
		            Class<?> value = (Class<?>) types[1];
		            Serialized<?> keySerialized = Register.getInstance().getSerialized(key);
		            Serialized<?> valueSerialized = Register.getInstance().getSerialized(value);
		            imports.add(keySerialized.getClass().getName());
		            imports.add(valueSerialized.getClass().getName());
		            imports.add(MapSerialized.class.getName());
		            imports.add(Map.class.getName());
				}
			}
		}
		
	}

}
